package org.apache.dolphinscheduler.api.service.impl;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.dolphinscheduler.api.dto.MonitorDto;
import org.apache.dolphinscheduler.api.enums.Status;
import org.apache.dolphinscheduler.api.service.OverviewService;
import org.apache.dolphinscheduler.api.service.UsersService;
import org.apache.dolphinscheduler.api.service.WorkerGroupService;
import org.apache.dolphinscheduler.api.utils.PageInfo;
import org.apache.dolphinscheduler.api.utils.Result;
import org.apache.dolphinscheduler.common.constants.Constants;
import org.apache.dolphinscheduler.common.utils.DateUtils;
import org.apache.dolphinscheduler.dao.entity.ProcessInstance;
import org.apache.dolphinscheduler.dao.entity.User;
import org.apache.dolphinscheduler.dao.mapper.OverviewMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.YearMonth;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class OverviewServiceImpl extends BaseServiceImpl implements OverviewService {

    @Autowired
    OverviewMapper overviewMapper;

    @Autowired
    UsersService usersService;

    @Autowired
    private WorkerGroupService workerGroupService;

    @Override
    public Integer getProcessDefinitionNum(User loginUser) {
        return overviewMapper.getProcessDefinitionNum(loginUser.getId());
    }

    @Override
    public Integer getFileNum(User loginUser) {
        return overviewMapper.getFileNum(loginUser.getId());
    }

    @Override
    public Integer getUDFNum(User loginUser) {
        return overviewMapper.getUDFNum(loginUser.getId()) + overviewMapper.getUDFNumFromResource(loginUser.getId());
    }

    @Override
    public Integer getDatasourceNum(User loginUser) {
        return overviewMapper.getDatasourceNum(loginUser.getId());
    }

    public Result queryProcessInstanceLatest10(User loginUser, Integer pageNo, Integer pageSize) {

        Result result = new Result();

        // userId 值为1表示admin
        int userId = loginUser.getId();

        // 查询该用户拥有权限的项目（自己创建的、赋权的、公共的），admin拥有所有项目的权限
        List<Long> projectCodeList = overviewMapper.getProjectCodeByUser(userId);

        Page<ProcessInstance> page = new Page<>(pageNo, pageSize);
        PageInfo<ProcessInstance> pageInfo = new PageInfo<>(pageNo, pageSize);

        IPage<ProcessInstance> processInstanceList = overviewMapper.getProcessInstanceLatest10(page, projectCodeList);

        List<ProcessInstance> processInstances = processInstanceList.getRecords();

        List<Integer> userIds = Collections.emptyList();
        if (CollectionUtils.isNotEmpty(processInstances)) {
            userIds = processInstances.stream().map(ProcessInstance::getExecutorId).collect(Collectors.toList());
        }
        List<User> users = usersService.queryUser(userIds);
        Map<Integer, User> idToUserMap = Collections.emptyMap();
        if (CollectionUtils.isNotEmpty(users)) {
            idToUserMap = users.stream().collect(Collectors.toMap(User::getId, Function.identity()));
        }

        for (ProcessInstance processInstance : processInstances) {
            processInstance.setDuration(DateUtils.format2Duration(processInstance.getStartTime(), processInstance.getEndTime()));
            User executor = idToUserMap.get(processInstance.getExecutorId());
            if (null != executor) {
                processInstance.setExecutorName(executor.getUserName());
            }
        }

        pageInfo.setTotal((int) processInstanceList.getTotal());
        pageInfo.setTotalList(processInstances);
        result.setData(pageInfo);
        result.setCode(Status.SUCCESS.getCode());
        return result;
    }

    @Override
    public Map<String, Object> queryHomeStatistics(User loginUser) {

        Map<String, Object> result = new HashMap<>();
        Map<String, Object> data = new HashMap<>();
        data.put("totalCpuNum", 0);
        data.put("totalGpuNum", 0);
        // 查询所有worker监控数据
        Map<String, MonitorDto> workerMonitorData = workerGroupService.queryWorkerMonitorData();
        if (CollectionUtils.isNotEmpty(workerMonitorData.values())) {
            int totalCpuNum = BigDecimal.valueOf(workerMonitorData.values().stream().mapToInt(MonitorDto::getCpuNum).sum())
                    .setScale(2, RoundingMode.HALF_UP).intValue();
            // cpu总核数
            data.put("totalCpuNum", totalCpuNum);
            int workerGpuNum = 0;
            for (MonitorDto monitorDto : workerMonitorData.values()) {
                String gpuInfoStr = monitorDto.getGpuInfos();
                if (StringUtils.isEmpty(gpuInfoStr) || gpuInfoStr.trim().equalsIgnoreCase("null")) {
                    continue;
                }
                JSONArray gpuInfoArray = JSONObject.parseArray(gpuInfoStr);
                if(gpuInfoArray != null) {
                	for(int i=0;i<gpuInfoArray.size();i++) {
                		JSONObject obj = gpuInfoArray.getJSONObject(i);
                		Integer ops = obj.getInteger("ops");
                		workerGpuNum += ops;
                	}
                }
            }
            data.put("totalGpuNum", workerGpuNum);
        }
        result.put(Constants.DATA_LIST, data);
        putMsg(result, Status.SUCCESS);
        return result;
    }

    @Override
    public Map<String, Object> queryProcessScene(User loginUser, String startDate, String endDate) {
        Map<String, Object> result = new HashMap<>();
        Map<String, Object> resultMap = new HashMap<>();
        resultMap.put("0", 0);
        resultMap.put("1", 0);
        resultMap.put("2", 0);
        if (StringUtils.isNotBlank(startDate) && StringUtils.isNotBlank(endDate)) {
            YearMonth start = YearMonth.parse(startDate, DateTimeFormatter.ofPattern("yyyy-MM"));
            YearMonth end = YearMonth.parse(endDate, DateTimeFormatter.ofPattern("yyyy-MM"));
            // 2023-08-01 00:00:00
            startDate = DateUtils.format(DateUtils.getStartOfDay(Date.from(start.atDay(1).atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())), Constants.YYYY_MM_DD_HH_MM_SS);
            // 2023-08-31 23:59:59
            endDate = DateUtils.format(DateUtils.getEndOfDay(Date.from(end.atEndOfMonth().atStartOfDay().atZone(ZoneId.systemDefault()).toInstant())), Constants.YYYY_MM_DD_HH_MM_SS);
        }
        List<Map<String, Object>> sceneMap = overviewMapper.queryProcessScene(loginUser.getId(), startDate, endDate);
        if (sceneMap.size() != 0) {
            for (Map<String, Object> map : sceneMap) {
                String scene = String.valueOf(map.get("scene"));
                resultMap.put(scene, map.get("num"));
            }
        }
        result.put(Constants.DATA_LIST, resultMap);
        putMsg(result, Status.SUCCESS);
        return result;
    }
}
